﻿using System;
using System.Data;
using System.Data.Common;
using System.IO;
using SlamCms.Common;
using SlamCms.Configuration;

namespace SlamCms.Data
{
	public class DefaultDbConnectionResolver : IDbConnectionResolver
	{
		private readonly string _connectionString;
		private readonly string _providerName = "System.Data.SqlClient";
		private readonly DbConnection _existingConnection;

		public DefaultDbConnectionResolver()
		{
		}

		public DefaultDbConnectionResolver(string connectionString, string providerName = "System.Data.SqlClient")
		{
			_connectionString = connectionString;
			_providerName = providerName;
		}

		public DefaultDbConnectionResolver(DbConnection connection)
		{
			_existingConnection = connection;
		}

		public string ConnectionString
		{
			get
			{
				return GetConnectionString().ConnectionString;
			}
		}

		public virtual DbConnection GetConnection()
		{
			if (_existingConnection != null)
				return _existingConnection;

			var connectionString = GetConnectionString();
			var connectionFactory = DbProviderFactories.GetFactory(connectionString.ProviderName);
			var connection = connectionFactory.CreateConnection();
			if (connection == null)
				throw new Exception("Cannot create connection for provider {0}".F(connectionString.ProviderName));

			connection.ConnectionString = connectionString.ConnectionString;

			Open(connection);

			return connection;
		}

		protected virtual void Open(DbConnection connection)
		{
			if (connection.State != ConnectionState.Open)
				connection.Open();
		}

		protected virtual ConnectionStringData GetConnectionString()
		{
			if (_existingConnection != null)
				return ConnectionStringData.Create("ExistingConnection", _existingConnection.ConnectionString, string.Empty);

			if (!_connectionString.IsNullOrEmpty())
				return ConnectionStringData.Create("ProvidedConnectionString", _connectionString, _providerName);

			if (!SlamCmsConfiguration.Instance.ConnectionString.IsNullOrEmpty())
			{
				var connectionString = SlamCmsConfiguration.Instance.ConnectionString;
				return ConnectionStringData.Create("SlamCmsConfiguration.ConnectionString", connectionString, _providerName);
			}

			try
			{
				if (ConfigurationManager.Environment.ConnectionStrings.Count > 0)
				{
					var connectionString = ConfigurationManager.Environment.DefaultConnectionString;
					return ConnectionStringData.Create(connectionString.Name, connectionString.ConnectionString, _providerName);
				}
			}
			catch (FileNotFoundException) 
			{ 
				// ignore this 
			}
			catch (DirectoryNotFoundException)
			{
				// ignore this
			}

			if (System.Configuration.ConfigurationManager.ConnectionStrings.Count > 0)
			{
				var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings[0];
				return ConnectionStringData.Create(connectionString.Name, connectionString.ConnectionString, connectionString.ProviderName ?? _providerName);
			}

			throw new Exception("There is no ConnectionString defined");
		}

		protected class ConnectionStringData
		{
			public static ConnectionStringData Create(string name, string connectionString, string providerName)
			{
				return new ConnectionStringData
						   {
							   Name = name,
							   ConnectionString = connectionString,
							   ProviderName = providerName
						   };
			}

			public string Name { get; set; }
			public string ProviderName { get; set; }
			public string ConnectionString { get; set; }
		}

		public override string ToString()
		{
			var connectionString = GetConnectionString();
			return "{0}|{1}|{2}".F(connectionString.Name, connectionString.ConnectionString, connectionString.ProviderName);
		}
	}
}
